package com.moefor.blog.model.vo;

import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.*;

public class VoModel {
    private Map<String, Object> field;

    private Object source;

    private List<String> defaultIgnoreProperties;

    public VoModel(Object source, String... defaultIgnoreProperties) throws IllegalAccessException {
        field = new HashMap<>();
        this.source = source;
        Class tempClass = source.getClass();
        while (tempClass != null){
            for(Field field : tempClass.getDeclaredFields()){
                field.setAccessible(true);
                this.field.put(field.getName(), field.get(source));
            }
            tempClass = tempClass.getSuperclass();
        }
        this.defaultIgnoreProperties = new ArrayList<>();
        this.defaultIgnoreProperties.addAll(Arrays.asList(defaultIgnoreProperties));
    }

    public VoModel hiddenField(String... fields) throws NoSuchFieldException, IllegalAccessException {
        for(String field : fields){
            remove(this.field, field);
        }
        return this;
    }

    private void remove(Map<String, Object> map, String field) throws IllegalAccessException {
        int dotIndex = field.indexOf('.')+1;
        if(dotIndex > 0){
            Field subClassField = ReflectionUtils.findField(source.getClass(), field.substring(0, dotIndex-1));
            subClassField.setAccessible(true);
            Map<String, Object> subMap = new HashMap<>();
            map.putIfAbsent(subClassField.getName(), subMap);
            Class tempClass = (subClassField.get(source)).getClass();
            while (tempClass != null){
                for(Field subField : tempClass.getDeclaredFields()){
                    subField.setAccessible(true);
                    if(!defaultIgnoreProperties.contains(subField.getName())) subMap.put(subField.getName(), subField.get(subClassField.get(source)));
                }
                tempClass = tempClass.getSuperclass();
            }
            remove(subMap, field.substring(dotIndex));
        }else {
            map.remove(field);
        }
    }

    public Map<String, Object> getVoModel(){
        return this.field;
    }
}
